﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Reflection;
using Neodynamic.SDK.Printing;
using System.ComponentModel.Design;
using System.IO;

namespace TLWindowsEditorWinFormsDemo
{
    //Based on https://stackoverflow.com/a/46102589

    public class ColorHexEditor : UITypeEditor
    {
        public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            return System.Drawing.Design.UITypeEditorEditStyle.Modal;
        }

        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            string colorHex = (string)value;

            ColorDialog cd = new ColorDialog();
            cd.Color = ColorTranslator.FromHtml(colorHex);
            if (cd.ShowDialog() == DialogResult.OK)
                colorHex = ColorTranslator.ToHtml(cd.Color);
            return colorHex;
        }
    }

    public class ImageFileEditor : UITypeEditor
    {
        public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            return System.Drawing.Design.UITypeEditorEditStyle.Modal;
        }

        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            string filePath = (string)value;

            OpenFileDialog ofd = new OpenFileDialog();
            ofd.FileName = filePath;
            ofd.Filter = "Image files (*.jpg, *.jpeg, *.png)|*.jpg;*.jpeg;*.png";
            if (ofd.ShowDialog() == DialogResult.OK)
                filePath = ofd.FileName;
            return filePath;
        }
    }

    /// <summary>
    /// ChangeLog:by IT_MAOFY 2025/02/11
    /// 1.增加文件选择，自动转换为Base64字符串
    /// </summary>
    public class ImageFileBase64Editor : UITypeEditor
    {
        public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            return System.Drawing.Design.UITypeEditorEditStyle.Modal;
        }

        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            string filePath = (string)value;

            OpenFileDialog ofd = new OpenFileDialog();
            ofd.FileName = filePath;
            ofd.Filter = "Image files (*.jpg, *.jpeg, *.png,*.bmp)|*.jpg;*.jpeg;*.png;*.bmp";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                filePath = ofd.FileName;

                var fileBytes = FileHelper.ReadFile(filePath);
                var base64 = Convert.ToBase64String(fileBytes);
                return base64;
            }
            return filePath;
        }

        
    }

    public class ExpressionUIEditor : UITypeEditor
    {
        public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            return System.Drawing.Design.UITypeEditorEditStyle.Modal;
        }

        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            string expr = (string)value;

            Global.ExprEditor.Expression = expr;

            if (Global.ExprEditor.ShowDialog() == DialogResult.OK)
                expr = Global.ExprEditor.Expression;

            return expr;
        }
    }


    public class DataFieldConverter : StringConverter
    {
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            return true;
        }

        public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {

            if (Global.DataFields != null && Global.DataFields.Count > 0)
                return new StandardValuesCollection(Global.DataFields);
            else
                return null;
            
        }

        public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
        {
            return false;
        }
        
    }

    /// <summary>
    /// ChangeLog: by IT_MAOFY 2025/02/10
    /// 1.增加中文注释
    /// </summary>
    public class TextItemMetadata
    {
        [Browsable(false)]
        public string InputMaskPattern { get; set; }
        [Browsable(false)]
        public char InputMaskPromptChar { get; set; }

        [Editor(typeof(ColorHexEditor), typeof(UITypeEditor)),Description("背景色(十六进制)"), Browsable(false)]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string BackColorHex { get; set; }

        [Editor(typeof(ColorHexEditor), typeof(UITypeEditor)), Description("边框颜色(十六进制)"), Browsable(false)]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string BorderColorHex { get; set; }

        [Editor(typeof(ColorHexEditor), typeof(UITypeEditor)), Description("前置颜色(十六进制)"), Browsable(false)]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string ForeColorHex { get; set; }

        [Editor(typeof(ColorHexEditor), typeof(UITypeEditor)), Browsable(false)]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string StrokeColorHex { get; set; }

        //[Browsable(false)]
        public double StrokeThickness { get; set; }

        [Editor(typeof(MultilineStringEditor), typeof(UITypeEditor)),Description("文本")]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string Text { get; set; }

       
        [Description("字符间距")]
        public double CharSpacing { get; set; }

        [Description("高度")]
        public double Height { get; set; }

        [Description("行间距")]
        public double LineSpacing { get; set; }

        [Description("文本化")]
        public TextSizing Sizing { get; set; }

        [Description("文本填充")]
        public TextSizing TextPadding { get; set; }

        [Description("宽度")]
        public bool Width { get; set; }

        [Browsable(false),Description("计数器步骤")]
        public int CounterStep { get; set; }

        [Browsable(false), Description("计数器使用前导零")]
        public bool CounterUseLeadingZeros { get; set; }

        //[TypeConverter(typeof(TextAlignmentConverter))]
        //public TextAlignment TextAlignment { get; set; }
        [Description("掩码")]
        public string Mask { get; set; }

        [Description("掩码增量")]
        public string MaskIncrement { get; set; }
        [Description("语言名称，如：zh-CN")]
        public string CultureName { get; set; }

        [Description("背景色")]
        public Neodynamic.SDK.Printing.Color BackColor { get; set; }

        [Description("边框颜色")]
        public Neodynamic.SDK.Printing.Color BorderColor { get; set; }

        [Description("圆角半径")]
        public RectangleCornerRadius CornerRadius { get; set; }

        [Description("边框宽度")]
        public FrameThickness BorderThickness { get; set; }

        [Description("前景色")]
        public Neodynamic.SDK.Printing.Color ForeColor { get; set; }

        [Description("旋转角度")]
        public int RotationAngle { get; set; }

        [Description("文字对齐方式")]
        public TextAlignment TextAlignment { get; set; }

        [Description("文本垂直对齐")]
        public TextVerticalAlignment TextVerticalAlignment { get; set; }

        [Description("如果为空则隐藏")]
        public bool HideIfEmpty { get; set; }

        [Description("验证的表达式"), Browsable(false)]
        public string ValidationRegEx { get; set; }

        [Description("验证的错误信息"), Browsable(false)]
        public string ValidationErrorMessage { get; set; }

        [Description("多行")]
        public bool Multiline { get; set; }

        [Description("最大长度")]
        public int MaxLength { get; set; }

        [Description("从右到左")]
        public bool RightToLeft { get; set; }

        [Description("字体")]
        public Neodynamic.SDK.Printing.Font Font { get; }
    }
    public class FontMetadata 
    {
        [Description("删除")]
        public bool Strikeout { get; set; }
        [Description("单位")]
        public FontUnit Unit { get; set; }
        [Browsable(false)]
        public string CustomFontFile { get; set; }
        [Description("代码页")]
        public CodePage CodePage { get; set; }

        [Description("是否为位图字体")]
        public bool IsBitmapFont { get; set; }

        [Description("阈值")]
        public int Threshold { get; set; }

        [Description("下划线")]
        public bool Underline { get; set; }

        [Browsable(false)]
        public string CustomFontFileFamilyName { get; set; }

        [Description("斜体")]
        public bool Italic { get; set; }

        [Description("字体名称")]
        public string Name { get; set; }
        [Description("大小")]
        public double Size { get; set; }

        [ Browsable(false)]
        public string NameAtPrinterStorage { get; set; }

        [Browsable(false)]
        public bool IsNativePrinterFont { get; }

        [Description("粗体")]
        public bool Bold { get; set; }
    }
    public class FrameThicknessMetadata
    {
        [Description("左边")]
        public double Left { get; set; }

        [Description("顶端")]
        public double Top { get; set; }

        [Description("底部")]
        public double Bottom { get; set; }

        [Description("右边")]
        public double Right { get; set; }
    }

    public class RectangleCornerRadiusMetadata 
    {
        [Description("左上角")]
        public double TopLeft { get; set; }

        [Description("右上角")]
        public double TopRight { get; set; }

        [Description("右下角")]
        public double BottomRight { get; set; }

        [Description("左下角")]
        public double BottomLeft { get; set; }
    }

    public class BarcodeItemMetadata
    {
        [Editor(typeof(ColorHexEditor), typeof(UITypeEditor)), Browsable(false)]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string BackColorHex { get; set; }

        [Editor(typeof(ColorHexEditor), typeof(UITypeEditor)), Browsable(false)]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string BorderColorHex { get; set; }

        [Editor(typeof(ColorHexEditor), typeof(UITypeEditor)), Browsable(false)]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string ForeColorHex { get; set; }

        [Editor(typeof(ColorHexEditor), typeof(UITypeEditor)), Browsable(false)]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string TextForeColorHex { get; set; }

        [Editor(typeof(ColorHexEditor), typeof(UITypeEditor)),Browsable(false)]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string BarColorHex { get; set; }

        [Browsable(false)]
        public BarcodeSymbology Symbology { get; set; }

        [Description("条形码对齐")]
        public BarcodeAlignment BarcodeAlignment { get; set; }

        [Description("条形码填充")]
        public FrameThickness BarcodePadding { get; set; }

        [Description("高")]
        public double Height { get; set; }

        [Description("条码尺寸")]
        public BarcodeSizing Sizing { get; set; }

        [Description("宽")]
        public double Width { get; set; }

        [Description("条宽")]
        public double BarWidth { get; set; }

        [Description("条宽调整")]
        public double BarWidthAdjustment { get; set; }

        [Description("条高")]
        public double BarHeight { get; set; }

        [Description("条宽比")]

        public double BarRatio { get; set; }

        [Description("保护框厚度")]
        public double BearerBarThickness { get; set; }

        [Description("保护框样式")]
        public BearerBarStyle BearerBarStyle { get; set; }

        [Description("条码的值"),Category("Data")]
        public string Code { get; set; }

        [Description("Code 128字符集")]
        public Code128 Code128CharSet { get; set; }

        [Description("空白区")]
        public FrameThickness QuietZone { get; set; }

        [Browsable(false)]
        public int CounterStep { get; set; }

        [Browsable(false)]
        public bool CounterUseLeadingZeros { get; set; }

        [Description("掩码")]
        public string Mask { get; set; }

        [Description("掩码增量")]
        public string MaskIncrement { get; set; }

        [Description("背景色")]
        public Neodynamic.SDK.Printing.Color BackColor { get; set; }

        [Description("条形图颜色")]
        public Neodynamic.SDK.Printing.Color BarColor { get; set; }

        [Description("边框颜色")]
        public Neodynamic.SDK.Printing.Color BorderColor { get; set; }

        [Description("边框宽度")]
        public FrameThickness BorderThickness { get; set; }

        [Description("代码对齐方式")]
        public BarcodeTextAlignment CodeAlignment { get; set; }

        [Description("圆角半径")]
        public RectangleCornerRadius CornerRadius { get; set; }

        [Description("前景色")]
        public Neodynamic.SDK.Printing.Color ForeColor { get; set; }

        [Description("可读文本")]
        public string HumanReadableText { get; set; }

        [Description("旋转角度")]
        public int RotationAngle { get; set; }

        [Description("代码字体")]
        public Neodynamic.SDK.Printing.Font Font { get; }

        [Description("文本")]
        public string Text { get; set; }

        [Description("文本对齐方式")]
        public BarcodeTextAlignment TextAlignment { get; set; }

        [Description("文本字体")]
        public Neodynamic.SDK.Printing.Font TextFont { get; }

        [Description("文本前景色")]
        public Neodynamic.SDK.Printing.Color TextForeColor { get; set; }

        [Description("代码格式模式")]
        public string CodeFormatPattern { get; set; }

        [Description("显示代码")]
        public bool DisplayCode { get; set; }

        [Description("错误行为")]
        public BarcodeErrorBehavior ErrorBehavior { get; set; }

        [Description("如果为空则隐藏")]
        public bool HideIfEmpty { get; set; }

        [Browsable(false)]
        public bool PrintAsResidentElement { get; set; }

        [Description("从右到左")]
        public bool RightToLeft { get; set; }

        [Description("文本格式模式")]
        public string TextFormatPattern { get; set; }

        [Browsable(false)]
        public bool UseQuietZoneForText { get; set; }

        [Description("二维码字节编码名称")]
        public string QRCodeByteEncodingName { get; set; }

        [Description("二维码编码")]
        public QRCodeEncoding QRCodeEncoding { get; set; }

        [Description("二维码纠错等级")]
        public QRCodeErrorCorrectionLevel QRCodeErrorCorrectionLevel { get; set; }


        [Description("二维码掩码")]
        public QRCodeMask QRCodeMask { get; set; }

        [Description("二维码模块尺寸")]
        public double QRCodeModuleSize { get; set; }

        [Description("二维码版本")]
        public QRCodeVersion QRCodeVersion { get; set; }


  




        /*
         *  [Category("Barcode Settings")]
        [Expressionable]
        public Supplement EanUpcSupplement { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public string DataMatrixByteEncodingName { get; set; }

        [Category("Barcode Settings")]
        [Expressionable]
        public int DataMatrixSymbolIndex { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public string DataMatrixFileId { get; set; }

        [Category("Barcode Settings")]
        [Expressionable]
        public int SegmentsPerRow { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public int DataMatrixSymbolCount { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public MsiChecksum MsiChecksum { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public MicroPdf417Version MicroPdf417Version { get; set; }

        
        [Category("Barcode Settings")]
        [Expressionable]
        public double AztecCodeModuleSize { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public AztecCodeFormat AztecCodeFormat { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public int AztecCodeErrorCorrection { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public int AztecCodeRune { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public string AztecCodeByteEncodingName { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public int Pdf417SegmentIndex { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public int Pdf417SegmentCount { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public string Pdf417FileId { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double Pdf417AspectRatio { get; set; }
 
        [Category("Barcode Settings")]
        [Expressionable]
        public Isbt128DataStructure Isbt128DataStructure { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool HibcFormatHumanReadableText { get; set; }


        [Category("Barcode Settings")]
        [Expressionable]
        public MicroQRCodeVersion MicroQRCodeVersion { get; set; }


        [Category("Barcode Settings")]
        [Expressionable]
        public bool GS1DataStrictValidation { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool MaxiCodeDrawPixelBasedSymbol { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double DotCodeModuleSize { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool DotCodeProcessTilde { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public int DotCodeColumns { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public int DotCodeRows { get; set; }

        [Category("Barcode Settings")]
        [Expressionable]
        public string DotCodeAspectRatio { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool DataMatrixIncludeRectFormatsInAutoMode { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool Code11TwoDigitsChecksum { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double Tlc39MicroPdf417BarWidth { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double Tlc39MicroPdf417RowBarHeight { get; set; }
    
        [Category("Barcode Settings")]
        [Expressionable]
        public RectMicroQRCodeVersion RectMicroQRCodeVersion { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public DotCodeModuleShape DotCodeModuleShape { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public ItfHmark Itf14RightHMark { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public ItfHmark Itf14LeftHMark { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool HanXinCodeProcessTilde { get; set; }


       
 
        [Category("Barcode Settings")]
        [Expressionable]
        public float EanUpcMagnificationFactor { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool HibcUseIsoIec15434Encoding { get; set; }
 
     
        [Category("Barcode Settings")]
        [Expressionable]
        public string HanXinCodeByteEncodingName { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public HanXinCodeEncoding HanXinCodeEncoding { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public HanXinCodeErrorCorrectionLevel HanXinCodeErrorCorrectionLevel { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public HanXinCodeVersion HanXinCodeVersion { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double HanXinCodeModuleSize { get; set; }

        [Category("Barcode Settings")]
        [Expressionable]
        public double PharmacodeThickBarWidth { get; set; }
  
        [Category("Barcode Settings")]
        [Expressionable]
        public double DataMatrixModuleSize { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool Code93FullAsciiMode { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool Code39FullAsciiMode { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public Code16k Code16kMode { get; set; }

    
      
        [Category("Barcode Settings")]
        [Expressionable]
        public bool DisplayChecksum { get; set; }
 
 
        [Category("Barcode Settings")]
        [Expressionable]
        public double PostnetHeightShortBar { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double PostnetHeightTallBar { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double PlanetHeightShortBar { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public DataMatrixFormat DataMatrixFormat { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double PlanetHeightTallBar { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double EanUpcGuardBarHeight { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool EanUpcGuardBar { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool AddChecksum { get; set; }

        [Category("Barcode Settings")]
        [Expressionable]
        public bool DisplayStartStopChar { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public CodabarStartStopChar CodabarStopChar { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public CodabarStartStopChar CodabarStartChar { get; set; }
     
      

      
 
        [Category("Barcode Settings")]
        [Expressionable]
        public DataMatrixEncoding DataMatrixEncoding { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool DataMatrixProcessTilde { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double EanUpcSupplementTopMargin { get; set; }
     

     
        [Category("Barcode Settings")]
        [Expressionable]
        public double PharmacodeBarsSpacing { get; set; }
 
        [Category("Barcode Settings")]
        [Expressionable]
        public double PharmacodeThinBarWidth { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public TelepenEncoding TelepenEncoding { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public int UspsHorizontalBarsCount { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public FIM UspsFimPattern { get; set; }

  
        [Category("Barcode Settings")]
        [Expressionable]
        public double EanUpcSupplementSeparation { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public string EanUpcSupplementCode { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public UpcE UpcESystem { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public int Pdf417Rows { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool EanUpcDisplayLightMarginIndicator { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public Pdf417ErrorCorrection Pdf417ErrorCorrectionLevel { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public Pdf417CompactionType Pdf417CompactionType { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public int Pdf417Columns { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public string Pdf417ByteEncodingName { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double Postal4StateTrackerBarHeight { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double Postal4StateTrackerBarWidth { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public double Postal4StateBarsSpacing { get; set; }
        [Category("Barcode Settings")]
        [Expressionable]
        public bool Postal4StateAddStartStopChar { get; set; }
   
        [Category("Barcode Settings")]
        [Expressionable]
        public bool Pdf417Truncated { get; set; }
        */
    }

    /// <summary>
    /// 方框元数据
    /// </summary>
    public class RectangleShapeItemMetadata
    {
        [Description("旋转角度")]
        public int RotationAngle { get; set; }

        [Description("圆角半径")]
        public RectangleCornerRadius CornerRadius { get; set; }
    }

    /// <summary>
    /// 直线元数据
    /// </summary>

    public class LineShapeItemMetadata 
    {
        [Description("方向")]
        public LineOrientation Orientation { get; set; }
    }

    public class ShapeItemMetadata
    {
        [Editor(typeof(ColorHexEditor), typeof(UITypeEditor)),Browsable(false)]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string StrokeColorHex { get; set; }

        [Description("笔画厚度")]
        public double StrokeThickness { get; set; }

        [Description("笔画颜色")]
        public Neodynamic.SDK.Printing.Color StrokeColor { get; set; }

        [Description("宽度")]
        public double Width { get; set; }

        [Description("高度")]
        public double Height { get; set; }

        [Description("笔画样式")]
        public StrokeStyle StrokeStyle { get; set; }

        [Browsable(false)]
        public string StrokeStylePattern { get; set; }
    }

    public class ClosedShapeItemMetadata
    {
        [Editor(typeof(ColorHexEditor), typeof(UITypeEditor)),Browsable(false)]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string FillColorHex { get; set; }

        [Description("填充的颜色")]
        public Neodynamic.SDK.Printing.Color FillColor { get; set; }
    }

    public class ImageItemMetadata
    {
        [Browsable(false)]
        [Editor(typeof(ImageFileEditor), typeof(UITypeEditor)), Category("Data")]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string SourceFile { get; set; }

        [Browsable(false)]
        public string NameAtPrinterStorage { get; set; }
   
        [Description("如果未找到则隐藏")]
        public bool HideIfNotFound { get; set; }

        [Browsable(false)]
        public bool IsGrayscaleOrBlackWhite { get; set; }

        [Description("锁定纵横比")]
        public LockAspectRatio LockAspectRatio { get; set; }
     
        [Description("快速翻转")]
        public Flip Flip { get; set; }

        [Description("旋转角度")]
        public int RotationAngle { get; set; }
    
        [Description("单色设置"),Category("Design")]
        public MonochromeSettings MonochromeSettings { get; }

        [Description("高")]
        public double Height { get; set; }
        [Description("宽")]
        public double Width { get; set; }

        [Browsable(false)]
        public byte[] SourceBinary { get; set; }

        [Editor(typeof(ImageFileBase64Editor), typeof(UITypeEditor)), Category("Data"), Description("图片的Base64字符串")]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string SourceBase64 { get; set; }

        [Browsable(false)]
        [Description("DPI")]
        public int SourceDpi { get; set; }

        [Description("转换为单色"),Browsable(false)]
        public bool ConvertToMonochrome { get; set; }
    }

    public class MonochromeSettingsMetadata 
    {
        [Description("抖动方法")]
        public DitherMethod DitherMethod { get; set; }
        [Description("阈值")]
        public int Threshold { get; set; }

        [Description("反向效果")]
        public bool ReverseEffect { get; set; }
    }


    /// <summary>
    /// ChangeLog: by IT_MAOFY 2025/02/10
    /// 增加中文注释
    /// </summary>
    public class ItemMetadata
    {
        [Browsable(false)]
        public bool Editable { get; set; }

        [Browsable(false)]
        public bool IsDesignTime { get; set; }

        [Editor(typeof(ExpressionUIEditor), typeof(UITypeEditor)), Description("表达式")]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string Expression { get; set; }

        [TypeConverter(typeof(DataFieldConverter)),Description("数据字段")]
        public string DataField { get; set; }

        [Browsable(false)]
        public bool GroupName { get; set; }

        [Description("锁定")]
        public bool Locked { get; set; }

        [Description("名称"), Browsable(false)]
        public string Name { get; set; }

        [Editor(typeof(MultilineStringEditor), typeof(UITypeEditor)), Description("说明"),Browsable(false)]
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public string Comments { get; set; }

        [Description("只读"),Browsable(false)]
        public bool ReadOnly { get; set; }

        [Description("可调整大小"), Browsable(false)]
        public bool Resizable { get; set; }

        [Description("标签"), Browsable(false)]
        public string Tag { get; set; }

        [Description("数据字段格式字符串"), Browsable(false)]
        public string DataFieldFormatString { get; set; }
        [Browsable(false)]
        public string CacheItemId { get; set; }

        [Browsable(false)]
        public bool UseCache { get; set; }

        [Browsable(false)]
        public bool Visible { get; set; }

        [Browsable(false)]
        public bool PrintAsGraphic { get; set; }
    }

    //public class FontMetadata
    //{
    //    [TypeConverter(typeof(FontNameConverter))]
    //    public string Name { get; set; }
    //}

    //public class FontNameConverter : StringConverter
    //{
    //    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    //    {
    //        return true;
    //    }

    //    public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    //    {
    //        var myFonts = new List<string>();

    //        myFonts.Add("Arial");
    //        myFonts.Add("ZPL Font 0");

    //        return new StandardValuesCollection(myFonts);
    //    }

    //    public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
    //    {
    //        return false;
    //    }

    //}

    //public class TextAlignmentConverter : EnumConverter
    //{
    //    public TextAlignmentConverter() : base(typeof(Neodynamic.SDK.Printing.TextAlignment))
    //    {
    //    }
    //    public override StandardValuesCollection GetStandardValues(
    //        ITypeDescriptorContext context)
    //    {
    //        var vals = new List<Neodynamic.SDK.Printing.TextAlignment> { Neodynamic.SDK.Printing.TextAlignment.Left, Neodynamic.SDK.Printing.TextAlignment.Right, Neodynamic.SDK.Printing.TextAlignment.Center };

    //        return new StandardValuesCollection(vals);
    //    }
    //}

    //Based on https://stackoverflow.com/a/51618536
    public class CustomItemWrapper : CustomTypeDescriptor
    {
        public object WrappedObject { get; private set; }
        public List<string> BrowsableProperties { get; private set; }
        public CustomItemWrapper(object o)
            : base(TypeDescriptor.GetProvider(o).GetTypeDescriptor(o))
        {
            WrappedObject = o;

            var browsableProps = new List<string>();

            if (o is BarcodeItem) {

                string[] properties = BarcodeItemUtils.GetRelatedProperties(((BarcodeItem)o).Symbology);
                BrowsableProperties = new List<string>(properties);
            }
            else {

                var props = o.GetType().GetProperties();
                foreach (var p in props)
                {
                    browsableProps.Add(p.Name);
                }

                BrowsableProperties = browsableProps;

                
            }
        }
        public override PropertyDescriptorCollection GetProperties()
        {
            return this.GetProperties(new Attribute[] { });
        }
        public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            var properties = base.GetProperties(attributes).Cast<PropertyDescriptor>()
                                 .Where(p => BrowsableProperties.Contains(p.Name))
                                 .Select(p => TypeDescriptor.CreateProperty(
                                     WrappedObject.GetType(),
                                     p,
                                     p.Attributes.Cast<Attribute>().ToArray()))
                                 .ToArray();
            return new PropertyDescriptorCollection(properties);
        }
    }


    //Declare a class that inherits from ToolStripControlHost.
    public class ToolStripSymbols : ToolStripControlHost
    {
        
        public ToolStripSymbols() : base(new UCSymbols()) {

            UCSymbolsControl.CreateSymbolsFromFont(Convert.FromBase64String(Global.CustomSymbolFontBase64), "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");

            UCSymbolsControl.Size = new Size(500, 440);

            UCSymbolsControl.MinimumSize = UCSymbolsControl.Size;

        }



        public UCSymbols UCSymbolsControl
        {
            get
            {
                return Control as UCSymbols;
            }
        }

        

        // Subscribe and unsubscribe the control events you wish to expose.
        protected override void OnSubscribeControlEvents(Control c)
        {
            // Call the base so the base events are connected.
            base.OnSubscribeControlEvents(c);

            // Cast the control to a UCSymbols control.
            UCSymbols symbolsControl = (UCSymbols)c;

            // Add the event.
            symbolsControl.SymbolChanged += new EventHandler(OnSymbolChanged);
        }

        protected override void OnUnsubscribeControlEvents(Control c)
        {
            // Call the base method so the basic events are unsubscribed.
            base.OnUnsubscribeControlEvents(c);

            // Cast the control to a UCSymbols control.
            UCSymbols symbolsControl = (UCSymbols)c;

            // Remove the event.
            symbolsControl.SymbolChanged -= new EventHandler(OnSymbolChanged);
        }

        // Declare the SymbolChanged event.
        public event EventHandler SymbolChanged;

        // Raise the SymbolChanged event.
        private void OnSymbolChanged(object sender, EventArgs e)
        {
            if (SymbolChanged != null)
            {
                SymbolChanged(sender, e);
            }
        }
    }

    #region DropDown Table Sizer
    // Credits
    // https://www.codeproject.com/Articles/15892/Adding-a-Custom-Control-to-a-ToolStripDropDownButt


    public class TableSizeEventArgs : EventArgs
    {
        public TableSizeEventArgs(Size selectedSize)
        {
            this.selectedSize = selectedSize;
        }

        public Size SelectedSize
        {
            get { return this.selectedSize; }
        }

        private Size selectedSize;
    }

    public delegate void TableSizeSelectedEventHandler(object sender, TableSizeEventArgs e);

    class TableSizeControl : Control
    {
        public event TableSizeSelectedEventHandler TableSizeSelected;
        public event EventHandler SelectionCancelled;

        public TableSizeControl()
        {
            DoubleBuffered = true;

            SetStyle(ControlStyles.ResizeRedraw, true);
            UpdateLayout();
        }

        public int CellSpacing
        {
            get { return this.cellSpacing; }
            set
            {
                if (value <= 0 || value + 1 > CellSize)
                    throw new ArgumentOutOfRangeException();

                if (this.cellSpacing != value)
                {
                    this.cellSpacing = value;
                    UpdateLayout();
                }
            }
        }

        public int CellSize
        {
            get { return this.cellSize; }
            set
            {
                if (value <= 4)
                    throw new ArgumentOutOfRangeException();

                if (this.cellSize != value)
                {
                    this.cellSize = value;
                    UpdateLayout();
                }
            }
        }

        public Size MinimumRange
        {
            get { return this.minimumRange; }
            set
            {
                if ((value.Width < 0 || value.Height < 0) ||
                    (value.Width > 0 && value.Width >= this.maximumRange.Width) ||
                    (value.Height > 0 && value.Height >= this.maximumRange.Height))
                    throw new ArgumentOutOfRangeException();

                this.minimumRange = value;
                SelectedSize = ConstrainSizeToLimits(SelectedSize);
            }
        }

        public Size MaximumRange
        {
            get { return this.maximumRange; }
            set
            {
                if ((value.Width < 0 || value.Height < 0) ||
                    (value.Width > 0 && value.Width <= this.minimumRange.Width) ||
                    (value.Height > 0 && value.Height <= this.minimumRange.Height))
                    throw new ArgumentOutOfRangeException();

                this.maximumRange = value;
                SelectedSize = ConstrainSizeToLimits(SelectedSize);
                VisibleRange = ConstrainSizeToLimits(VisibleRange);
            }
        }

        public Size VisibleRange
        {
            get { return this.visibleRange; }
            set
            {
                Size size = ConstrainSizeToLimits(value);

                if (this.visibleRange != size)
                {
                    this.visibleRange = size;
                    UpdateLayout();
                }
            }
        }

        public Size SelectedSize
        {
            get { return this.checkedRange; }
            set
            {
                Size size = ConstrainSizeToLimits(value);

                if (this.checkedRange != size)
                {
                    this.checkedRange = size;

                    buttonText = (this.checkedRange.Width > 0 && this.checkedRange.Height > 0) ?
                        String.Format("{0} x {1} Table", this.checkedRange.Width, this.checkedRange.Height) :
                        "Cancel";

                    Invalidate();
                }

                size.Width = Math.Max(size.Width, VisibleRange.Width);
                size.Height = Math.Max(size.Height, VisibleRange.Height);
                VisibleRange = size;
            }
        }

        protected enum HitPart
        {
            Border,
            Pool,
            Button,
        }

        protected struct HitInfo
        {
            public HitPart part;
            public int col;
            public int row;
        }

        protected HitInfo QueryHit(Point pt)
        {
            HitInfo info = new HitInfo();

            Rectangle poolBounds = PoolBounds;

            if (poolBounds.Contains(pt))
            {
                info.part = HitPart.Pool;
                info.col = (pt.X - poolBounds.X) / CellSize;
                info.row = (pt.Y - poolBounds.Y) / CellSize;
            }
            else
            {
                info.part = (pt.Y > poolBounds.Bottom) ? HitPart.Button : HitPart.Border;
                info.col = -1;
                info.row = -1;
            }

            return info;
        }

        protected virtual void OnSelectionCancelled(EventArgs e)
        {
            if (SelectionCancelled != null)
                SelectionCancelled(this, e);
        }

        protected virtual void OnTableSizeSelected(TableSizeEventArgs e)
        {
            if (TableSizeSelected != null)
                TableSizeSelected(this, e);
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);

            if (Visible)
                this.selectUsingMouse = true;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Brush brush = new SolidBrush(this.selectedColor);

            using (Pen pen = new Pen(this.borderColor))
            {
                int extent = CellSize - CellSpacing - 1;

                Rectangle cellRect = new Rectangle(0, PoolBounds.Top, extent, extent);

                for (int row = 0; row < visibleRange.Height; ++row, cellRect.Y += CellSize)
                {
                    cellRect.X = PoolBounds.Left;

                    for (int col = 0; col < visibleRange.Width; ++col, cellRect.X += CellSize)
                    {
                        if (col < checkedRange.Width && row < checkedRange.Height)
                            e.Graphics.FillRectangle(brush, cellRect);

                        e.Graphics.DrawRectangle(pen, cellRect);
                    }
                }
            }

            brush.Dispose();

            using (Brush textBrush = new SolidBrush(this.textColor))
            {
                Rectangle bounds = ClientRectangle;
                bounds.Y = PoolBounds.Bottom + CellSpacing;
                bounds.Height = Font.Height;

                StringFormat format = new StringFormat();
                format.LineAlignment = StringAlignment.Center;
                format.Alignment = StringAlignment.Center;

                e.Graphics.DrawString(buttonText, Font, textBrush, bounds, format);
            }
        }

        protected override bool ProcessDialogKey(Keys keyData)
        {
            bool eatKey = true;

            Size newCheckedRange = SelectedSize;

            switch (keyData)
            {
                case Keys.Up:
                    {
                        this.selectUsingMouse = false;

                        if (newCheckedRange.Height > 0)
                            --newCheckedRange.Height;
                        break;
                    }

                case Keys.Down:
                    {
                        this.selectUsingMouse = false;

                        ++newCheckedRange.Height;
                        newCheckedRange.Width = Math.Max(1, newCheckedRange.Width);
                        break;
                    }

                case Keys.Left:
                    {
                        this.selectUsingMouse = false;

                        if (newCheckedRange.Width > 0)
                            --newCheckedRange.Width;
                        break;
                    }

                case Keys.Right:
                    {
                        this.selectUsingMouse = false;

                        ++newCheckedRange.Width;
                        newCheckedRange.Height = Math.Max(1, newCheckedRange.Height);
                        break;
                    }

                case Keys.Cancel:
                    {
                        OnSelectionCancelled(new EventArgs());
                        break;
                    }

                case Keys.Enter:
                    {
                        EndSelection();
                        break;
                    }

                default:
                    eatKey = false;
                    break;
            }

            SetSelection(newCheckedRange);

            return eatKey || base.ProcessDialogKey(keyData);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            HitInfo hit = QueryHit(e.Location);

            if (!this.selectUsingMouse || hit.part == HitPart.Button)
            {
                Capture = false;
                EndSelection();
            }
            else if (hit.part == HitPart.Pool)
            {
                if (this.selectUsingMouse)
                    ExpandPoolToPt(e.Location);

                Capture = true;
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            if (Capture)
            {
                Capture = false;
                EndSelection();
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (this.selectUsingMouse)
            {
                HitInfo hit = QueryHit(e.Location);

                if (Capture)
                    ExpandPoolToPt(e.Location);

                SelectedSize = (hit.part == HitPart.Pool) ?
                    new Size(hit.col + 1, hit.row + 1) :
                    new Size(0, 0);
            }
        }

        #region Implementation

        private Rectangle PoolBounds
        {
            get
            {
                int cx = CellSize * VisibleRange.Width;
                int cy = CellSize * VisibleRange.Height;

                return new Rectangle(CellSpacing * 2, CellSpacing, cx, cy);
            }
        }

        private Size LayoutSize
        {
            get { return PoolBounds.Size + new Size(CellSpacing * 3, CellSpacing * 2 + Font.Height); }
        }

        private void UpdateLayout()
        {
            this.Size = LayoutSize;
        }

        private void SetSelection(Size size)
        {
            if (SelectedSize != ConstrainSizeToLimits(size))
            {
                SelectedSize = size;

                ExpandPool(
                    new Size(
                        Math.Max(0, SelectedSize.Width - VisibleRange.Width),
                        Math.Max(0, SelectedSize.Height - VisibleRange.Height)));
            }
        }

        private void EndSelection()
        {
            if (SelectedSize.Width > 0 && SelectedSize.Height > 0)
                OnTableSizeSelected(new TableSizeEventArgs(SelectedSize));
            else
                OnSelectionCancelled(new EventArgs());
        }

        private Size ConstrainSizeToLimits(Size size)
        {
            if (MinimumRange.Width > 0)
                size.Width = Math.Max(MinimumRange.Width, size.Width);

            if (MaximumRange.Width > 0)
                size.Width = Math.Min(MaximumRange.Width, size.Width);

            if (MinimumRange.Height > 0)
                size.Height = Math.Max(MinimumRange.Height, size.Height);

            if (MaximumRange.Height > 0)
                size.Height = Math.Min(MaximumRange.Height, size.Height);

            return size;
        }

        private void ExpandPoolToPt(Point pt)
        {
            Rectangle bounds = PoolBounds;

            Size growSize = new Size(0, 0);

            if (pt.X > bounds.Right - CellSpacing)
                growSize.Width = (pt.X - bounds.Right) / CellSize + 1;

            if (pt.Y > bounds.Bottom - CellSpacing)
                growSize.Height = (pt.Y - bounds.Bottom) / CellSize + 1;

            ExpandPool(growSize);
        }

        private void ExpandPool(Size sizeIncrease)
        {
            Size newSize = VisibleRange;

            if (sizeIncrease.Width > 0)
                if (MaximumRange.Width <= 0 || VisibleRange.Width + sizeIncrease.Width <= MaximumRange.Width)
                    newSize.Width += sizeIncrease.Width;

            if (sizeIncrease.Height > 0)
                if (MaximumRange.Height <= 0 || VisibleRange.Height + sizeIncrease.Height <= MaximumRange.Height)
                    newSize.Height += sizeIncrease.Height;

            VisibleRange = newSize;
        }
        #endregion

        // Model state
        private Size minimumRange = new Size(0, 0);
        private Size maximumRange = new Size(10, 10);
        private Size visibleRange = new Size(5, 4);
        private Size checkedRange = new Size(0, 0);

        private string buttonText = "Cancel";

        // Presentation
        private int cellSize = 24;
        private int cellSpacing = 2;

        private System.Drawing.Color selectedColor = SystemColors.Highlight;
        private System.Drawing.Color borderColor = SystemColors.WindowText;
        private System.Drawing.Color textColor = SystemColors.WindowText;

        // Interaction state
        private bool selectUsingMouse = true;
    }

    class ToolStripTableSizeSelector : ToolStripDropDown
    {
        public ToolStripTableSizeSelector()
        {
            Items.Add(new ToolStripControlHost(control));

            control.TableSizeSelected += new TableSizeSelectedEventHandler(control_TableSizeSelected);
            control.SelectionCancelled += new EventHandler(control_SelectionCancelled);
        }

        public TableSizeControl Selector
        {
            get { return this.control; }
        }

        private void control_SelectionCancelled(object sender, EventArgs e)
        {
            this.Close(ToolStripDropDownCloseReason.CloseCalled);
        }

        private void control_TableSizeSelected(object sender, TableSizeEventArgs e)
        {
            this.Close(ToolStripDropDownCloseReason.CloseCalled);
        }

        protected override void OnOpening(System.ComponentModel.CancelEventArgs e)
        {
            base.OnOpening(e);

            ToolStripProfessionalRenderer renderer = Renderer as ToolStripProfessionalRenderer;

            if (renderer != null)
                control.BackColor = renderer.ColorTable.ToolStripDropDownBackground;

            //control.SelectedSize = new Size(0, 0);
            //control.VisibleRange = new Size(5, 4);
        }

        protected override void OnOpened(EventArgs e)
        {
            base.OnOpened(e);
            control.Focus();
        }

        private TableSizeControl control = new TableSizeControl();
    }
    #endregion
}
